对象存储,从单机到分布式的演进
通过《什么是云存储?从对象存储说起》我们对对象存储的历史、概念和基本使用有了一个大概的认识。而且我们以Minio为例,通过单机部署的模式实际操作了一下对象存储的GUI,感受了一下对象存储的用法。
在上例中,对象存储软件部署在一台服务器上,称为一个单机版的对象存储系统。单机版的对象存储系统其实可以非常简单,可以是如下图所示的架构,上层是协议层,用于解析客户端的请求;下层是存储层,用于对设备内的硬盘进行管理,并实现数据的存储。
在实际生产中并不会使用单机部署的对象存储,原因是如果服务器宕机,那么我们就无法访问其中的数据了,也就是所谓的单点故障问题。除了上面说的单点问题外,还有就是单台服务器的处理能力和存储能力有限,通常无法满足互联网大规模访问的性能和容量需求。
所以,对于企业级的对象存储,通常采用的是分布式的架构,也就是数据会被存储在多个节点上。而且对象存储的性能和容量可以与节点总数量有一个近似线性的关系,也就是节点越多,性能越高,容量也越大。
那么如何将数据放置到多个节点呢?这就涉及到两种不同的数据放置方法,一种是分片(Sharding),另外一种称为副本(Replication)。下面我们分别解释一下上面两个概念。
分片技术其实最早来源于数据库领域。当一个数据库承载的数据太多时,单数据库实例不堪重负,这时就会考虑分库分表的操作。所谓分库分表就是将该业务的数据集进行拆分,放在不同的数据库实例当中。也就是通过多个数据库实例来承载业务数据。分库分表本身涉及非常多的原则,处理细节也不尽相同,我们不再这里详述。这里想告诉大家的是,分片技术其实就是将一个数据集合分散存储在多个节点(服务器)上的技术。
分布式对象存储借鉴了数据库的分片技术,通过某种算法将对象集合分散到不同的节点上。虽然在底层数据是分散在多个节点上的,但给用户呈现的单一的命名空间,也就是用户并不会感知到底层是由多个节点构成的。如下图所示,当用户通过统一的接口存储的3个对象,经过某种算法后会被存储在三个不同的节点上。
分片算法有很多种实现,比如常见的一致性哈希和Ceph的CRUSH算法等。虽然算法各有差异,但是其核心思想是将数据均匀的放置到多个节点上,并且在增加或者减少节点的时候尽量减少数据的迁移。
另外一种技术就是副本技术,副本技术将同一份数据存储在多个节点。如下图是一个三副本的示例,同一份数据被存储在三个不同的节点上。副本技术在一定程度上也能提高系统性能,通常采用一写多读的方式,也就是一个副本可以读写,称为主副本;其它副本只能读,称为从副本。
副本技术除了可以提供存储系统的性能外,还有一个非常重要的功能是提高数据的可靠性。在基于分片架构的存储系统中,如果一个节点宕机,那么其上的数据就不能访问。副本技术将同一份数据放置在多个节点上,即使某个节点宕机,仍然可以通过其它节点访问数据。
副本技术虽然可以提高系统性能,保证数据的可靠性,但是却浪费了比较多的空间。上述3副本的系统为例,假设每个节点的存储容量是1TB,那么最多只能存储1TB的数据。而上述采用分片技术的架构可以存储3TB的数据,所以存储系统有效容量非常低,只有33%。
为了解决存储有效容量低的问题,出现了另外一种演化版本,也就是纠删码技术。纠删码技术不是简单的将数据存储在多个节点上,而是将原始数据切割为若干数据块,并计算出多个校验数据块,然后将原始数据块和校验数据块存储在不同的节点上。当原始数据块或者校验数据块所在的节点宕机的情况下,可以通过其它数据块重新计算出来,这样就避免了单点故障。同时,由于校验数据块的比例相对于副本方式要少的多,因此有效数据容量也大的多。以下图为例,采用2+1的纠删码,有效存储容量可以达到66%。而且实际生产环境数据的有效容量会更高,比如微软云采用10+2,有效存储容量可以达到83.3%。
通过前面分析我们知道分片技术可以线性提升存储的容量和性能,但是数据可靠性没有保证。而副本技术无法提升存储容量,提升性能也有限,但可以有效提高数据的可靠性。所以在对象存储产品中通常会同时采用这两种技术,也就是对两种技术进行融合。通过两种技术的融合,既可以保证存储系统的横向扩展性,又可以保证数据的可靠性。
基于上述技术,分布式对象存储的架构简图可以如下图所示,在协议层的下面增加了一个路由层。当协议层解析完请求后,路由层会根据自身算法和请求的特征实现路由,由具体的节点完成后续工作。
虽然大体的原理如此,但各个产品在实现细节上还是有不少差异的。接下来我们以OpenStack Swift为例介绍一下具体的实现。这里之所以选择开源产品是因为大家可以安装部署,并进行相关的验证。